package com.scau402.system1.service.impl;

import com.github.pagehelper.PageInfo;
import com.scau402.common.core.domain.AjaxResult;
import com.scau402.common.core.domain.entity.SysUser;
import com.scau402.common.core.page.TableDataInfo;
import com.scau402.common.utils.DataUtils;
import com.scau402.common.utils.DateUtils;
import com.scau402.common.utils.PageUtils;
import com.scau402.common.utils.SecurityUtils;
import com.scau402.constants.BusinessException;
import com.scau402.constants.RabbitConstants;
import com.scau402.system.constants.SystemConstants;
import com.scau402.system1.domain.dto.*;
import com.scau402.system1.domain.po.*;
import com.scau402.system1.domain.query.WmsCheckBoundOrderQuery;
import com.scau402.system1.domain.vo.WmsCheckBoundJadeDetailVO;
import com.scau402.system1.domain.vo.WmsCheckBoundOrderDetailVO;
import com.scau402.system1.domain.vo.WmsCheckBoundOrderVO;
import com.scau402.system1.mapper.*;
import com.scau402.system1.repository.*;
import com.scau402.system1.service.IWmsCheckBoundOrderService;
import com.scau402.system1.utils.IdGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.sql.Wrapper;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 盘点单Service实现类
 * @since 2024/1/27
 */
@Service
@Transactional
@Slf4j
public class IWmsCheckBoundOrderServiceImpl implements IWmsCheckBoundOrderService {
    @Autowired
    private IWmsCheckboundOrderMapper wmsCheckboundOrderMapper;
    @Autowired
    private WmsJadeMapperV2 wmsJadeMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private IWmsCheckOrderRepository checkOrderRepo;
    @Autowired
    private IWmsCheckDetailRepository checkDetailRepo;
    @Autowired
    private IWmsCheckJadeDetailRepository checkJadeDetailRepo;
    @Autowired
    private IWmsJadeRepository jadeRepo;
    @Autowired
    private IWmsWarehouseRepository warehouseRepo;
    @Autowired
    private IWmsStorageRepository storageRepo;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private IWmsAdjustOrderRepository adjustOrderRepo;
    @Autowired
    private IWmsCheckboundWareStorageMapper wmsCheckboundWareStorageMapper;

    /**
     * 创建盘点单
     * @param checkOrderDTO 创建信息
     * @return 创建结果
     * @since 2024/1/27
     */
    @Override
    public AjaxResult createCheckOrder(WmsCheckBoundOrderDTO checkOrderDTO) {
        IdGenerator idGenerator = new IdGenerator(stringRedisTemplate);
        // 获取用户信息
        SysUser user = SecurityUtils.getLoginUser().getUser();

        // 仓库与仓位的参数校验
        // TODO: 后续可能要用其他DDD代替
        List<WarehouseStorage> targetList = checkOrderDTO.getTargetList();

        // 校验
        for (int i = 0; i < targetList.size(); i++) {
            WarehouseStorage target = targetList.get(i);
            Long warehouseId = target.getWarehouseId();
            Long storageId = target.getStorageId();
            try {
                // 检查是否存在已经开启的冲突盘点
                // 检查仓库是否在盘点
                List<Long> wIds = checkOrderRepo.findActiveOrderByWarehouseId(warehouseId);
                if (!wIds.isEmpty()) throw new BusinessException(SystemConstants.WAREHOUSE_CHECKING);
                if(storageId!=null){
                    // 检查仓位是否在盘点
                    List<Long> sIds = checkOrderRepo.findActiveOrderByStorageId(storageId);
                    if(!sIds.isEmpty()) throw new BusinessException(SystemConstants.STORAGE_CHECKING);
                }
                // 判断是否存在进行库存调整审核的相关货品
                if (adjustOrderRepo.checkIsAuditing(target) != -1L) {
                    throw new BusinessException(SystemConstants.CHECK_BOUND_AUDITING);
                }
            }catch (BusinessException e){
                return AjaxResult.error(e.getMessage());
            }
        }

        // 创建盘点单
        WmsCheckboundOrderDetailPO detailPO = new WmsCheckboundOrderDetailPO();
        WmsCheckBoundOrderPO normalPO = new WmsCheckBoundOrderPO(checkOrderDTO,idGenerator,user,detailPO);

        //获取新创建的盘点单id
        Long id = normalPO.getId();

        // 设置数量、价值等
        detailPO.setNumAndPrice(jadeRepo.countNumAndPrice2(targetList));

        // 生成对应翡翠的信息并加入数据库
        generateJadeDetail(targetList,idGenerator,normalPO.getId());

        checkOrderRepo.saveOrderWareStorageRelation(normalPO.getId(),targetList);

        // 加入数据库
        checkOrderRepo.save(normalPO,detailPO);

        return AjaxResult.success(id);
    }

    /**
     * 生成盘点单中对应的翡翠详情并加入数据库
     * @param targetList 盘点目标列表（仓库id、仓位id）
     * @param idGenerator id生成器
     * @param checkOrderId 盘点单id
     * @since 2024/1/28
     */
    private void generateJadeDetail(List<WarehouseStorage> targetList, IdGenerator idGenerator,Long checkOrderId) {

        for (WarehouseStorage warehouseStorage : targetList) {
            Long storageId = warehouseStorage.getStorageId(),warehouseId = warehouseStorage.getWarehouseId();
            List<WmsCheckboundJadeDetailPO> jadeDetailList;
//            jadeDetailList = jadeRepo.selectJadeDetailListByWarehouseStorage(targetList);
            // 未指定仓位
            if(storageId==null){
                // 获取仓库下所有翡翠信息
                jadeDetailList = jadeRepo.selectJadeDetailListByWarehouseId(warehouseId);
            }
            //指定了对应仓位
            else {
                // 获取仓位及其子仓位下的所有翡翠信息
                // 获取所有相关的仓位id
                List<Long> relatedStorageIds = getRelatedStorageIds(storageId);
                // 搜索相关jade信息
                jadeDetailList = jadeRepo.selectRelatedJadeDetail(warehouseId,relatedStorageIds);
            }
            //处理详情的图片id——取第一个翡翠的图片作为代表
            jadeDetailList = jadeDetailList.stream()
                    .peek(jade-> jade.setImageId(jadeRepo.selectOneImageIdByBarcode(jade.getBarcode())))
                    .collect(Collectors.toList());
            // 转换为对应详情类
            jadeDetailList.forEach(jade->{
                jade.setId(idGenerator.nextId("jadeDetail")).setCheckOrderId(checkOrderId);
            });
            if (jadeDetailList.isEmpty()) {
                continue;
            }
            //加入数据库
            checkJadeDetailRepo.saveList(jadeDetailList);
        }
    }

    /**
     * 获取仓位及其属下的仓位id
     * @param rootStorageId 根仓位id
     * @return 所有子仓位id的列表
     * @since 2024/1/28
     */
    private List<Long> getRelatedStorageIds(Long rootStorageId){
        List<Long> ids = new ArrayList<>();
        ids.add(rootStorageId);
        Queue<Long> queue = new ArrayDeque<>();
        queue.add(rootStorageId);
        while (!queue.isEmpty()) {
            Long id = queue.poll();
            //搜索id属下的所有子仓位
            List<Long> tempIds = storageRepo.findChildStorageIdById(id);
            //搜索到结果，加入结果集，继续搜索
            if(!tempIds.isEmpty()) {
                ids.addAll(tempIds);
                queue.addAll(tempIds);
            }
        }
        return ids;
    }

    /**
     * 计算盘点仓库的数量以及价值
     * @param wmsWarehouseDO 仓库信息
     * @param wmsWarehouseStoragePO 仓位信息
     * @param detailPO 详情
     * @since 2024/1/28
     * @deprecated 请使用IWmsJadeRepository中提供的同名方法
     */
    @Deprecated
    private void countNumAndPrice(WmsWarehouseDO wmsWarehouseDO, WmsWarehouseStoragePO wmsWarehouseStoragePO, WmsCheckboundOrderDetailPO detailPO) {
        Long warehouseId = wmsWarehouseDO.getId();
        Long storageId = -1L;
        CalWarehouseNumAndValueDTO NAV;
        //未指定仓位
        if(wmsWarehouseStoragePO ==null){
            // 计算仓库总价值和总量
            NAV = wmsJadeMapper.selectTotalPriceByWarehouseId(warehouseId);
        }
        //指定了对应仓位
        else {
            //计算仓位总价值和总量
            storageId = wmsWarehouseStoragePO.getId();
            NAV = wmsJadeMapper.selectTotalPriceByStorageId(storageId);
        }
        //设置总量
        detailPO.setTotalNum(NAV.getTotalNum());
        detailPO.setTotalPrice(NAV.getTotalValue());
        //初始化当前数量
        detailPO.setCurNum(0L);
        detailPO.setCurPrice(new BigDecimal(0));
    }

    /**
     * 获取盘点单信息列表
     * @return 结果列表
     * @since 2024/1/27
     */
    @Override
    public TableDataInfo listCheckOrder(WmsCheckBoundOrderQuery query) {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        String userName = user.getUserName();
        query.setTenantId(user.getTenantId());
        //分页
        PageUtils.startPage();
        List<WmsCheckBoundOrderVO> checkBoundOrderVOList = checkOrderRepo.findListByCreator(query);

        //加入MDC
        PageUtils.fetchSessionPageInfo(new PageInfo<>(checkBoundOrderVOList));
        if(DataUtils.isEmpty(checkBoundOrderVOList)){
            log.warn("查询结果为空，{}",userName);
            return new TableDataInfo();
        }
        return PageUtils.getDataTableFromList(checkBoundOrderVOList);
    }

    /**
     * 确认盘点
     * @param checkOrderId 盘点单id
     * @param barcode 翡翠条码
     * @param num 数量
     * @return 确认结果
     * @since 2024/1/27
     */
    @Override
    @Deprecated
    public AjaxResult confirm(Long checkOrderId,String barcode, Long num) {
        // 参数校验——checkOrderId 和 jadeCode
//        WmsCheckWareStorageBO wmsCheckWareStorageBO = wmsCheckboundOrderMapper.selectByOrderId(checkOrderId);
        WmsCheckBoundOrderPO wmsCheckBoundOrderPO = wmsCheckboundOrderMapper.selectById(checkOrderId);
        if(wmsCheckBoundOrderPO==null) return AjaxResult.error(SystemConstants.CHECK_BOUND_NOT_EXIST);
        if(wmsCheckBoundOrderPO.getStatus()=='1') return AjaxResult.error(SystemConstants.CHECK_BOUND_EXITED);

//        // 判断翡翠是否属于对应的仓库、仓位
//        // 获取条码对应的仓库id和仓位id
//        WmsJadePO jadePO = wmsJadeMapper.selectWareAStoIdByBarcode(barcode);
//        List<WmsCheckBoundWareStoragePO> wareStorageList = wmsCheckboundWareStorageMapper.selectList(new QueryWrapper<WmsCheckBoundWareStoragePO>().eq("check_order_id",checkOrderId));
////        Long warehouseId = wmsCheckBoundOrderPO.();
////        Long orderStorageId = wmsCheckBoundOrderPO.getStorageId();
//        Set<Long> idSet = new HashSet<>();
//        Set<Long> storageIdSet = wareStorageList.stream().map(WmsCheckBoundWareStoragePO::getStorageId).collect(Collectors.toSet());
//        Set<Long> warehouseIdSet = wareStorageList.stream().map(WmsCheckBoundWareStoragePO::getWarehouseId).collect(Collectors.toSet());
//        List<Long> storageList = wareStorageList.stream().map(WmsCheckBoundWareStoragePO::getStorageId).collect(Collectors.toList());
//        if(!warehouseIdSet.isEmpty()){
//            List<Long> relatedIds = getRelatedStorageIds(storageList);
//            idSet.addAll(relatedIds);
//            if(!idSet.contains(jadePO.getStorageId())) return AjaxResult.error(SystemConstants.STORAGE_WRONG);
//        }
//        else {
//            if(!warehouseId.equals(jadePO.getWarehouseId())) return AjaxResult.error(SystemConstants.WAREHOUSE_WRONG);
//        }

        // 更新翡翠详情的 已盘点数量
        WmsCheckboundJadeDetailPO jadeDetail = checkJadeDetailRepo.findJadeByBarcodeAndOrderId(barcode,checkOrderId);
        jadeDetail.setCountNums(jadeDetail.getCountNums()+num);

        // 更新盘点单明细的 已盘点数量 和 已盘点成本
        WmsCheckboundOrderDetailPO orderDetail = checkDetailRepo.findDetailByCheckOrderId(checkOrderId);
        orderDetail.updateNumAndPrice(num,jadeDetail);

        // 加入数据库
        checkJadeDetailRepo.update(jadeDetail,barcode,checkOrderId);
        checkDetailRepo.updateByCheckOrderId(orderDetail,checkOrderId);

        return AjaxResult.success();
    }

    /**
     * 获取盘点单详情
     * @param checkOrderId 盘点单号
     * @return 详情信息
     * @since 2024/1/27
     */
    @Override
    public AjaxResult getOrderDetail(Long checkOrderId) {
        WmsCheckBoundOrderPO wmsCheckBoundOrderPO = wmsCheckboundOrderMapper.selectById(checkOrderId);
        // TODO: 参数校验
        if(wmsCheckBoundOrderPO==null) return AjaxResult.error(SystemConstants.CHECK_BOUND_NOT_EXIST);

        WmsCheckBoundOrderDetailVO detailVO = checkDetailRepo.findOneByCheckOrderId(checkOrderId);

        return AjaxResult.success(detailVO);
    }

    /**
     * 获取盘点单对应翡翠的盘点详情
     * @param checkOrderId 盘点单号
     * @return 详情信息
     * @since 2024/1/27
     */
    @Override
    public TableDataInfo getJadesDetail(Long checkOrderId) {
//        WmsCheckBoundOrderPO wmsCheckBoundOrderPO = wmsCheckboundOrderMapper.selectById(checkOrderId);

//        //参数校验
//        if(wmsCheckBoundOrderPO==null) {
//            log.error("盘点单号不存在：{}",checkOrderId);
//            return new TableDataInfo();
//        }

        //分页
        PageUtils.startPage();

        List<WmsCheckBoundJadeDetailVO> jadeDetailVOList = checkJadeDetailRepo.findListByCheckOrderId(checkOrderId);
        //加入MDC
        PageUtils.fetchSessionPageInfo(new PageInfo<>(jadeDetailVOList));
        if(DataUtils.isEmpty(jadeDetailVOList)){
            log.warn("库存盘点单翡翠详情查询结果为空，盘点单号：{}",checkOrderId);
            return new TableDataInfo();
        }

        return PageUtils.getDataTableFromList(jadeDetailVOList);
    }

    /**
     * 停止盘点
     * @param checkOrderId 盘点单Id
     * @return 操作结果
     * @since 2024/1/27
     */
    @Override
    public AjaxResult stopCheckOrder(Long checkOrderId) {
        WmsCheckBoundOrderPO wmsCheckBoundOrderPO = checkOrderRepo.findById(checkOrderId);
        // TODO: 参数校验
        if(wmsCheckBoundOrderPO==null) return AjaxResult.error(SystemConstants.CHECK_BOUND_NOT_EXIST);
        if(wmsCheckBoundOrderPO.getStatus()=='1') return AjaxResult.error(SystemConstants.CHECK_BOUND_EXITED);

        // 获取盘点结果
        List<WmsCheckboundJadeDetailPO> jadeDetailPOList = checkJadeDetailRepo.findNumListByCheckOrderId(checkOrderId);

        //更新状态为盘点结算中
        checkOrderRepo.updateToChecking(wmsCheckBoundOrderPO.getId());

        //加入消息队列
        rabbitTemplate.convertAndSend(RabbitConstants.CHECK_QUEUE1,new StopCheckDTO(wmsCheckBoundOrderPO,jadeDetailPOList,null));

        return AjaxResult.success();
    }


    /**
     * 修改备注
     * @param wmsCheckOrderEditDTO
     * @return
     */
    @Override
    public AjaxResult editRemark(WmsCheckOrderEditDTO wmsCheckOrderEditDTO) {
        WmsCheckBoundOrderPO wmsCheckBoundOrderDTO=new WmsCheckBoundOrderPO();
        wmsCheckBoundOrderDTO.setRemark(wmsCheckOrderEditDTO.getRemark());
        wmsCheckBoundOrderDTO.setUpdateTime(LocalDateTime.now());
        checkOrderRepo.updateByCheckOrderId(wmsCheckBoundOrderDTO, wmsCheckOrderEditDTO.getCheckOrderId());
        return AjaxResult.success();
    }
}
